package com.sunlee.common.service.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sunlee.common.core.constant.Constant;
import com.sunlee.common.core.entity.PageData;
import com.sunlee.common.service.dao.ProductDao;
import com.sunlee.common.service.dto.ProductActionDTO;
import com.sunlee.common.service.dto.ProductDTO;
import com.sunlee.common.service.dto.ProductListDTO;
import com.sunlee.common.service.dto.req.ProductWaterfallsFlowDTO;
import com.sunlee.common.service.entity.ProductEntity;
import com.sunlee.common.service.enums.StatusEnum;
import com.sunlee.common.service.service.MarketingProductMappingService;
import com.sunlee.common.service.service.ProductCategoryMappingService;
import com.sunlee.common.service.service.ProductService;
import com.sunlee.common.service.service.UserActionService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.security.SecureRandom;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 商品表
 *
 * @author sunlee
 */
@Service
public class ProductServiceImpl extends CrudServiceImpl<ProductDao, ProductEntity, ProductDTO> implements ProductService {


    @Autowired
    private MarketingProductMappingService marketingProductMappingService;

    @Autowired
    private ProductCategoryMappingService productCategoryMappingService;

    @Autowired
    private UserActionService userActionService;

    @Override
    public LambdaQueryWrapper<ProductEntity> getWrapper(Map<String, Object> params) {
        LambdaQueryWrapper<ProductEntity> wrapper = new LambdaQueryWrapper<>();

        String id = (String) params.get("id");
        String keyword = (String) params.get("keyword");
        String status = (String) params.get("status");

        wrapper.eq(Objects.nonNull(status), ProductEntity::getStatus, status);
        wrapper.like(StringUtils.isNotBlank(id), ProductEntity::getId, id);
        if (StringUtils.isNotBlank(keyword)) {
            wrapper.and(w -> w.like(ProductEntity::getTitle, keyword)
                    .or()
                    .like(ProductEntity::getTag, keyword));
        }
        return wrapper;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteRelByIds(Long[] ids) {
        productCategoryMappingService.deleteByPIds(Arrays.asList(ids));
        marketingProductMappingService.deleteByPIds(Arrays.asList(ids));
        deleteOwn(ids);
    }

    @Override
    public PageData<ProductListDTO> searchPage(Map<String, Object> params) {
        Object keyword = params.get("keyword");

        LambdaQueryWrapper<ProductEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ProductEntity::getStatus, Constant.STATUS_VALID)
                .eq(ProductEntity::getStatus, StatusEnum.VALID.getCode())
                .orderByDesc(ProductEntity::getUpdateDate);

        if (keyword != null) {
            String keywordStr = (String) keyword;
            queryWrapper.like(ProductEntity::getName, keywordStr)
                    .or().like(ProductEntity::getTitle, keywordStr)
                    .or().like(ProductEntity::getShortDesc, keywordStr)
                    .or().like(ProductEntity::getTag, keywordStr);

        }

        IPage<ProductEntity> entityIpage = baseDao.selectPage(super.getPage(params, "", false), queryWrapper);
        PageData<ProductListDTO> pageData = getPageData(entityIpage, ProductListDTO.class);

        List<ProductListDTO> productList = pageData.getList();
        if (CollectionUtils.isEmpty(productList)) {
            return pageData;
        }
        List<Long> pIds = productList.stream().map(ProductListDTO::getId).collect(Collectors.toList());
        Map<Long, ProductActionDTO> productMap = userActionService.getProductActionDataByIds(pIds);

        productList.forEach(item -> {
            item.setActionData(productMap.get(item.getId()));
        });

        return pageData;
    }

    @Override
    public List<ProductEntity> selectList(LambdaQueryWrapper<ProductEntity> wrapper) {
        return baseDao.selectList(wrapper);
    }

    @Override
    public PageData<ProductDTO> homeWaterfallsFlow(ProductWaterfallsFlowDTO request) {

        LambdaQueryWrapper<ProductEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ProductEntity::getStatus, StatusEnum.VALID.getCode());

        // 前3页随机
        int randPage = 3;
        if (request.getPage() <= randPage) {
            wrapper.last("ORDER BY RAND()");
        } else {
            request.setPage(request.getPage() - randPage);
            wrapper.orderByDesc(ProductEntity::getUpdateDate);
        }

        Page<ProductEntity> page = new Page<>(request.getPage(), request.getLimit());
        Page<ProductEntity> productEntityPage = baseDao.selectPage(page, wrapper);

        PageData<ProductDTO> pageData = getPageData(productEntityPage, ProductDTO.class);

        List<ProductDTO> productDtoS = pageData.getList();

        // 设置下载、浏览、收藏数
        if (!CollectionUtils.isEmpty(productDtoS)) {
            List<Long> pIds = productDtoS.stream().map(ProductDTO::getId).collect(Collectors.toList());
            Map<Long, ProductActionDTO> productMap = userActionService.getProductActionDataByIds(pIds);
            for (ProductDTO item : productDtoS) {
                item.setActionData(productMap.get(item.getId()));
            }
        }
        return pageData;
    }

    @Override
    public List<ProductEntity> getAny(LambdaQueryWrapper<ProductEntity> wrapper, Integer limit) {

        int total = baseDao.selectCount(wrapper).intValue();
        if (limit == null || limit <= 0 || total == 0) {
            return Collections.emptyList();
        }
        List<ProductEntity> list = Optional.of(limit)
                .filter(l -> l > total)
                .map(l -> baseDao.selectList(wrapper))
                .orElseGet(() -> baseDao.selectList(
                        wrapper.last("LIMIT " + new SecureRandom().nextInt(total - (limit - 1)) + "," + limit)));
        Collections.shuffle(list);
        return list;
    }
}
